////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//                   PEER 2 PEER FILE SHARING SYSTEM                          //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////
package com.cse.p2p.common;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.XML;

/**
 * This class describes a DicFile content, which has the following information:
 * <ul>
 * <li><code>trackerURL</code> : The URL of the server which look for this file.
 * </li>
 * <li><code>fileID</code>: The unique ID of the file on the tracker</li>
 * <li><code>fileName</code>: The human-friendly file name for the user</li>
 * <li><code>fileSize</code>: The size (in byte) of the file</li>
 * <li><code>pieceSize</code>: The fixed size (in byte) of each piece when
 * download. It is needed when getting pieces</li>
 * <li><code>pieceHash</code>: The SHA-1 hash string of each piece, used when
 * validating pieces and file.</li>
 * </ul>
 * The <code>Parser</code> class will be used to generate the XML string from a
 * DicFile object as well as create a DicFile object from a XML file.
 * @author TrungHieu
 */
public class DicFile implements Serializable {

	// The name constant of json and xml strings

	public static final String NODE_ROOT = "dicfile";
	public static final String NODE_TRACKER_URL = "tracker";
	public static final String NODE_FILE_ID = "fileid";
	public static final String NODE_FILE_NAME = "filename";
	public static final String NODE_FILE_DESC = "filedesc";
	public static final String NODE_FILE_SIZE = "filesize";
	public static final String NODE_PIECE_SIZE = "piecesize";
	public static final String NODE_PIECE_HASH = "piecehash";
	
	public static final String FILE_EXT = "dic";
	public static final String FILE_EXT_DESC = "P2PShareIt Dic file";


	// the private members which hold the info of a DicFile

	private String trackerURL;
	private int fileID;
	private String fileName;
	private String fileDesc;
	private long fileSize;
	private long pieceSize;
	private Map pieceHash;

	public DicFile( String trackerURL, int fileID, String fileName, String fileDesc, long fileSize, long pieceSize, Map pieceHash ) {
		this.trackerURL = trackerURL;
		this.fileID = fileID;
		this.fileName = fileName;
		this.fileDesc = fileDesc;
		this.fileSize = fileSize;
		this.pieceSize = pieceSize;
		this.pieceHash = pieceHash;
	}

	public int getFileID() {
		return fileID;
	}

	public void setFileID( int fileID ) {
		this.fileID = fileID;
	}

	public String getFileName() {
		return fileName;
	}

	public void setFileName( String fileName ) {
		this.fileName = fileName;
	}

	public long getFileSize() {
		return fileSize;
	}

	public void setFileSize( long fileSize ) {
		this.fileSize = fileSize;
	}

	public Map getPieceHash() {
		return pieceHash;
	}

	public void setPieceHash( Map pieceHash ) {
		this.pieceHash = pieceHash;
	}

	public long getPieceSize() {
		return pieceSize;
	}

	public void setPieceSize( long pieceSize ) {
		this.pieceSize = pieceSize;
	}

	public String getTrackerURL() {
		return trackerURL;
	}

	public void setTrackerURL( String trackerURL ) {
		this.trackerURL = trackerURL;
	}

	public String getFileDesc() {
		return fileDesc;
	}

	public void setFileDesc( String fileDesc ) {
		this.fileDesc = fileDesc;
	}

	
	/**
	 * Create a {@link DicFile} object from an XML string. The XML string can
	 * be read by the <code>LocalFile</code> module. If there is a error, a
	 * {@link ParsingException} will be thrown.
	 *
	 * @param	XMLString	the string need to be parsed
	 * @return	a <code>DicFile</code> object
	 * @throws ParsingException
	 */
	public static DicFile parseDicFileFromXML( String XMLString ) {
		try {
			JSONObject jsObj = new JSONObject( XMLString );
			JSONArray hashArray = jsObj.getJSONObject( DicFile.NODE_ROOT ).getJSONArray( DicFile.NODE_PIECE_HASH );
			Map hashStrings = new HashMap();
			for ( int i = 0; i < hashArray.length(); i++ ) {
				hashStrings.put( i, hashArray.getString( i ) );
			}
			return new DicFile( jsObj.getJSONObject( DicFile.NODE_ROOT ).getString( DicFile.NODE_TRACKER_URL ),
								jsObj.getJSONObject( DicFile.NODE_ROOT ).getInt( DicFile.NODE_FILE_ID ),
								jsObj.getJSONObject( DicFile.NODE_ROOT ).getString( DicFile.NODE_FILE_NAME ),
								jsObj.getJSONObject( DicFile.NODE_ROOT ).getString( DicFile.NODE_FILE_DESC),
								jsObj.getJSONObject( DicFile.NODE_ROOT ).getInt( DicFile.NODE_FILE_SIZE ),
								jsObj.getJSONObject( DicFile.NODE_ROOT ).getInt( DicFile.NODE_PIECE_SIZE ),
								hashStrings );
		}
		catch ( JSONException e ) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * Generata a XML string from a {@link DicFile} object. The result can be
	 * written to a file and make it be a valid DicFile.
	 *
	 * @param	dicFile	The <code>DicFile</code> object need to be parsed
	 * @return	an XML string
	 * @throws ParsingException
	 */
	public static String XMLFromDicFile( DicFile dicFile ) {
		try {
			JSONObject jsObj = new JSONObject();
			jsObj.put( DicFile.NODE_TRACKER_URL, dicFile.getTrackerURL() );
			jsObj.put( DicFile.NODE_FILE_ID, dicFile.getFileID() );
			jsObj.put( DicFile.NODE_FILE_NAME, dicFile.getFileName() );
			jsObj.put( DicFile.NODE_FILE_DESC, dicFile.getFileDesc());
			jsObj.put( DicFile.NODE_FILE_SIZE, dicFile.getFileSize() );
			jsObj.put( DicFile.NODE_PIECE_SIZE, dicFile.getPieceSize() );
			jsObj.put( DicFile.NODE_PIECE_HASH, new JSONArray( dicFile.getPieceHash().values() ) );
			JSONObject jsWrap = new JSONObject();
			jsWrap.put( DicFile.NODE_ROOT, jsObj);
			return jsWrap.toString();
		}
		catch ( JSONException e ) {
			return null;
		}
	}
}
